package com.wyp.design.pattern.creational.singleton.reflectattack;


import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
 * 懒汉式加载以及线程安全
 *
 * @author: yipeng.wang01@hand-china.com-25490
 * @TIME: 2020/1/2/13:40
 **/
public class LazySingleton {
    private static LazySingleton lazySingleton = null;

    private static boolean flag = true;

    private LazySingleton() {
        if (flag) {
            flag = false;
        } else {
            throw new RuntimeException("单例模式禁止反射调用！");
        }
    }

    /**
     * synchronized 用在静态方法上是将整个类的class文件进行加锁。相当于方法体中使用
     * synchronized (LazySingleton.class) {
     * <p>
     * }
     * 这样使用锁的范围还是比较大的，对性能的影响还是比较大的，所以需要进行继续改进。
     *
     * @return
     */
    public static synchronized LazySingleton getInstance() {

        if (lazySingleton == null) {
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }

    public static void main(String[] args) throws Exception {

        //使用反射进行创建对象
        Class<LazySingleton> singletonClass = LazySingleton.class;
        //获取私有构造器
        Constructor<LazySingleton> constructor = singletonClass.getDeclaredConstructor();
        constructor.setAccessible(true);

        //先生成，后反射调用--可以有效的防止反射攻击，反射反射也可以进行修改私有字段的值，从而导致判断条件成立进行创建对象

        LazySingleton instance = LazySingleton.getInstance();

        //当第一次创建对象之后，flag值为false，使用反射进行修改为true
        Field flag = singletonClass.getDeclaredField("flag");
        flag.setAccessible(true);
        flag.set(flag,true);
        LazySingleton newInstance = constructor.newInstance();

        System.out.println(newInstance);
        System.out.println(instance);
        System.out.println(newInstance == instance);

    }
}
